package com.black.platform.permission.service.handler.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.black.common.auth.UserContextHolder;
import com.black.common.web.PageQuery;
import com.black.platform.menu.po.Menu;
import com.black.platform.menu.service.biz.MenuService;
import com.black.platform.permission.po.Permission;
import com.black.platform.permission.po.WhitePath;
import com.black.platform.permission.service.bz.PermissionService;
import com.black.platform.permission.service.bz.WhitePathService;
import com.black.platform.permission.service.handler.PermissionHandlerService;
import com.black.platform.permission.vo.PermissionTreeVo;
import com.black.common.vo.PermissionVo;
import com.black.platform.role.po.RolePermission;
import com.black.platform.role.service.bz.RolePermissionService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PermissionHandlerServiceImpl implements PermissionHandlerService {


    private final PermissionService permissionService;

    private final MenuService menuService;

    private final RolePermissionService rolePermissionService;

    private final WhitePathService whitePathService;

    @Override
    public IPage<Permission> search(PageQuery<Permission> searchVo) {
        return permissionService.search(searchVo);
    }

    @Override
    public Permission getById(Long id) {
        return permissionService.getById(id);
    }

    @Override
    @CacheEvict(value = {"UserMenu", "UserPermission"}, allEntries = true)
    public boolean saveOrUpdate(Permission permission) {
        if ("menu".equals(permission.getPermissionType())) {
            Menu menu = menuService.getById(permission.getMenuId());
            permission.setParentId(menu.getParentId());
            permission.setOrders(menu.getOrders());
        }
        return permissionService.saveOrUpdate(permission);
    }

    @Override
    @CacheEvict(value = {"UserMenu", "UserPermission"}, allEntries = true)
    public boolean removeByIds(List<Long> ids) {
        return permissionService.removeByIds(ids);
    }

    @Override
    public Map<String, List<PermissionTreeVo>> getPermissionTree(String systemCode) {
        QueryWrapper<Permission> query = new QueryWrapper<>();
        query.eq("system_code", systemCode);
        List<Permission> permissionList = permissionService.list(query);
        List<PermissionTreeVo> viewPermission = buildPermissionTreeTree(permissionList, Arrays.asList("button", "router"));
        List<PermissionTreeVo> dataPermission = buildPermissionTreeTree(permissionList, Collections.singletonList("data"));
        Map<String, List<PermissionTreeVo>> map = new HashMap<>();
        map.put("viewPermission", viewPermission);
        map.put("dataPermission", dataPermission);
        return map;
    }

    @Override
    public List<PermissionVo> getAllPermissionsByUser(String systemCode, boolean isIncludeInvalid) {
        return permissionService.getAllPermissionsByUser(UserContextHolder.getUserId(), systemCode, isIncludeInvalid);
    }

    @Override
    public List<PermissionVo> getAllDataPermissionsByUser(String systemCode) {
        return permissionService.getAllDataPermissionsByUser(UserContextHolder.getUserId(), systemCode);
    }

    @Override
    public List<String> getUserButtonPermissionsByUserId(String systemCode, boolean isIncludeInvalid) {
        return permissionService.getAllPermissionsByUser(UserContextHolder.getUserId(), systemCode, isIncludeInvalid)
                .stream().filter(permission -> "button".equals(permission.getPermissionType()))
                .map(PermissionVo::getPermissionCode).collect(Collectors.toList());
    }

    @Override
    public Map<String, Set<Long>> getAllRouterPermissions() {
        QueryWrapper<Permission> query = new QueryWrapper<>();
        query.eq("permission_type", "router");
        query.eq("valid", 1);
        List<Permission> list = permissionService.list(query);
        Set<Long> permissionIdSet = list.stream().map(Permission::getId).collect(Collectors.toSet());
        QueryWrapper<RolePermission> rolePermissionQuery = new QueryWrapper<>();
        rolePermissionQuery.in("permission_id", permissionIdSet);
        List<RolePermission> rolePermissionList = rolePermissionService.list(rolePermissionQuery);
        Map<String, Set<Long>> routerRoleMap = new HashMap<>();
        Map<Long, String> permissionMap = list.stream().collect(Collectors.toMap(Permission::getId, Permission::getPermissionCode));
        list.stream().map(Permission::getPermissionCode).forEach(item -> routerRoleMap.put(item, new HashSet<>()));
        rolePermissionList.forEach(item -> {
            String permissionCode = permissionMap.get(item.getPermissionId());
            if (!StringUtils.isEmpty(permissionCode)) {
                Set<Long> roleSet = routerRoleMap.get(permissionCode);
                roleSet.add(item.getRoleId());
            }
        });
        return routerRoleMap;
    }

    @Override
    public Set<String> getAllWhitePath() {
        QueryWrapper<WhitePath> query = new QueryWrapper<>();
        query.eq("valid", 1);
        List<WhitePath> list = whitePathService.list(query);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().map(WhitePath::getPath).collect(Collectors.toSet());
    }


    /***
     * 构建系统权限树
     * @param permissionList 系统权限集合
     * @return 系统权限树集
     */
    private List<PermissionTreeVo> buildPermissionTreeTree(List<Permission> permissionList, List<String> types) {
        List<PermissionTreeVo> voList = new ArrayList<>();
        List<Permission> subPermissionList = permissionList.stream().filter(permission -> types.contains(permission.getPermissionType())).collect(Collectors.toList());
        Map<Long, PermissionTreeVo> buttonMap = subPermissionList.stream().collect(Collectors.toMap(Permission::getId, permission -> {
            PermissionTreeVo permissionTreeVo = new PermissionTreeVo();
            permissionTreeVo.setId(permission.getId());
            permissionTreeVo.setTitle(permission.getPermissionName());
            permissionTreeVo.setType(permission.getPermissionType());
            permissionTreeVo.setPermissionCode(permission.getPermissionCode());
            return permissionTreeVo;
        }));
        // 菜单
        List<Permission> menuPermissionList = permissionList.stream().filter(permission -> "menu".equals(permission.getPermissionType())).collect(Collectors.toList());
        if (types.contains("data")) {
            List<Long> collect = subPermissionList.stream().map(Permission::getParentId).distinct().collect(Collectors.toList());
            if (collect.size() > 0) {
                menuPermissionList = menuPermissionList.stream().filter(permission -> collect.contains(permission.getMenuId())).collect(Collectors.toList());
            } else {
                return voList;
            }
        }
        if (menuPermissionList.size() == 0) {
            return voList;
        }
        Map<Long, PermissionTreeVo> voMap = menuPermissionList.stream().collect(Collectors.toMap(Permission::getMenuId, permission -> {
            PermissionTreeVo permissionTreeVo = new PermissionTreeVo();
            permissionTreeVo.setId(permission.getId());
            permissionTreeVo.setTitle(permission.getPermissionName());
            permissionTreeVo.setType(permission.getPermissionType());
            permissionTreeVo.setPermissionCode(permission.getPermissionCode());
            return permissionTreeVo;
        }));
        menuPermissionList.sort(Comparator.comparingInt(Permission::getOrders));
        for (Permission permission : menuPermissionList) {
            if (types.contains("data")) {
                voList.add(voMap.get(permission.getMenuId()));
            } else {
                if (StringUtils.isEmpty(permission.getParentId())) {
                    voList.add(voMap.get(permission.getMenuId()));
                } else {
                    if (voMap.get(permission.getParentId()).getChildren() == null) {
                        voMap.get(permission.getParentId()).setExpand(true);
                        voMap.get(permission.getParentId()).setChildren(new ArrayList<>());
                    }
                    voMap.get(permission.getParentId()).getChildren().add(voMap.get(permission.getMenuId()));
                }
            }
        }
        for (Permission permission : subPermissionList) {
            if (StringUtils.isEmpty(permission.getParentId())) {
                voList.add(buttonMap.get(permission.getId()));
            } else {
                if (voMap.get(permission.getParentId()).getChildren() == null) {
                    voMap.get(permission.getParentId()).setExpand(true);
                    voMap.get(permission.getParentId()).setChildren(new ArrayList<>());
                }
                voMap.get(permission.getParentId()).getChildren().add(buttonMap.get(permission.getId()));
            }
        }
        // 其他
        if (!types.contains("data")) {
            permissionList.stream().filter(permission -> "other".equals(permission.getPermissionType())).forEach(permission -> {
                PermissionTreeVo permissionTreeVo = new PermissionTreeVo();
                permissionTreeVo.setId(permission.getId());
                permissionTreeVo.setTitle(permission.getPermissionName());
                permissionTreeVo.setType(permission.getPermissionType());
                permissionTreeVo.setPermissionCode(permission.getPermissionCode());
                voList.add(permissionTreeVo);
            });
        }
        return voList;
    }
}
